#gevent :实现任务的自动切换
'''
其原理是当一个greenlet遇到IO操作时，比如访问网络，就自动切换
到其他的greenlet，等到IO操作完成，再适当的时候切换回来执行任务。

优于IO操作非常耗时，经常使程序处于等待状态，有了gevent为我们
自动切换协程，就保证总有greenlet在运行，而不是等待IO操作完。

安装 pip install gevent

语法：
创建协程对象 gevent.spawn(func函数名,参数)
gevent.spawn(funa,1,2,x=4)
join:阻塞，直到这个协程执行完毕  gevent.joinall()

'''
import gevent
def write():
    print('我要写作业')
    print('写完了')
def eat():
    print('我要吃零食')
    print('吃完了')

g1 = gevent.spawn(write)   #创建协程
g2 = gevent.spawn(eat)

g1.join()   #等待g1执行完毕
g2.join()   #等待g2执行完毕
print('=========================================================')
print('\n')


#任务自动切换
import gevent
def funa(n):
    for i in range(n):
        print(gevent.getcurrent(),i) #返回当前正在执行的greenlet
        #模拟一个耗时操作，注意不是time中的sleep
        gevent.sleep(1)

g1 = gevent.spawn(funa,2) #2表示funa参数
g2 = gevent.spawn(funa,2)
g3 = gevent.spawn(funa,2)

g1.join()   #等待g1执行完毕 jion效果是：按顺序执行
g2.join()
g3.join()
print('=========================================================')
print('\n')



#gevent,joinall()方法的参数是一个协程对象列表，它会等待所有协程
#都执行完毕后再退出。
'''
import gevent
import time
from gevent import monkey
monkey.patch_all()

def task(name):
    for i in range(3):
        print(f'函数名是：{name}，i的值是：{i}')
        time.sleep(1)   #打补丁gevent能识别，用来模拟耗时操作

gevent.joinall([
    gevent.spawn(task,'task1'),
    gevent.spawn(task,'task2')
])
'''

#综合案例---协程自动切换，减少任务执行时间
import gevent
import time

def boy():
    print('我有话想对你说')
    gevent.sleep(2)   #遇到gevent,sleep()耗时操作，协程自动切换
    print('能不能做我女朋友')

def girl():
    print('你python学好了吗？')
    gevent.sleep(3)
    print('学完了我就考虑一下')

def people():
    print('加油加油')
    gevent.sleep(4)
    print('继续嗑瓜子……')

t1 = time.time()    #时间戳 （秒）
gevent.joinall([
    gevent.spawn(boy),
    gevent.spawn(girl),
    gevent.spawn(people)
])                  #等待列表中的协程执行完毕
t2 = time.time()
print('运行时间：',(t2-t1))
print('=========================================================')
print('\n')




#进程、线程、协程对比及应用
'''
进程 > 线程 > 协程

1.进程是资源的单位，现成是操作系统调度的单位；
2.一个程序至少有一个进程，一个进程至少有一个线程；
3.协程切换任务需要的资源很小，效率高

并发：分时切片串行操作，实际上同一时间只有一个任务在运行
并行：可同时操作。

线程和进程的操作是程序触发系统接口，最后执行者是系统，协程的
操作则是操作员

应用场景：
CPU密集型：多进程
IO密集型：多线程
IO阻塞且需要大量并发的场景：协程
IO+CPU都密集：多进程+协程

举例：
多进程：多个qq登录，qq号之间无法沟通，进程间资源不共享
进程间通信：队列  共享消息队列

多线程：一个qq开多个聊天窗口
多个聊天窗口都是我一个人操作，我是这几个聊天窗口公有的资源
我同一个时间节点智能和一人聊天：线程并发
有人发抖动窗口或视频，让我被迫停止与其他人聊天赖接他的：线程资源竞争
给大家制定先来后到的选择，后来者要等待，解决资源竞争的办法：lock锁 + join


'''



